package com.hiultra.archive.device.door;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.gg.reader.api.dal.*;
import com.gg.reader.api.protocol.gx.*;
import com.hiultra.archive.config.MainConfig;
import com.hiultra.archive.domain.*;
import com.hiultra.archive.service.*;
import com.hiultra.common.constant.BusinessConstants;
import com.hiultra.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component("doorManager")
public class DoorManager {
    Log log = LogFactory.get();

    @Autowired
    MainConfig mainConfig;
    @Autowired
    private IArcBoxService arcBoxService;
    @Autowired
    private IArchiveBoxInoutRecordsService archiveBoxInoutRecordsService;
    @Autowired
    private IArchiveBoxInoutdetailService archiveBoxInoutDetailService;

    @Autowired
    private IArchiveBoxIllegalRecordsService archiveBoxIllegalRecordsService;

    @Autowired
    private IArchiveBoxIllegalDetailRecordsService archiveBoxIllegalDetailRecordsService;

    private GClient gClient;
    private boolean isConnect = false;
    private boolean isReading = false;
    private static LogAppGpiStart firstLogAppGpiStart;
    // 是进还是出
    private static Boolean isIn = null;
    private static Set<TagInfo> tagSet = new HashSet();
    private static volatile boolean isProcess = false;
    private static ExecutorService executorService = new ThreadPoolExecutor(1, 1,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>());

    @PostConstruct
    public void initDoor() {
        log.info("通道门初始化");
        gClient = new GClient();
        gClient.setSendHeartBeat(true);
        gClient.onDisconnected = new HandlerTcpDisconnected() {
            @Override
            public void log(String s) {
                isConnect = false;
                log.info("通道门断开连接");
            }
        };
        gClient.onTagEpcLog = new HandlerTagEpcLog() {
            @Override
            public void log(String s, LogBaseEpcInfo logBaseEpcInfo) {
//                tagLight(logBaseEpcInfo.getAntId());
                System.out.println("通道门-----------------收到标签");
                if (logBaseEpcInfo != null) {
                    System.out.println(logBaseEpcInfo);
                }
                if (logBaseEpcInfo.getEpc() != null && !logBaseEpcInfo.getEpc().isEmpty() && !tagSet.contains(logBaseEpcInfo)) {
                    tagSet.add(new TagInfo(logBaseEpcInfo.getTid(), logBaseEpcInfo.getEpc(), System.currentTimeMillis()));
                }
            }
        };
        gClient.onTagEpcOver = new HandlerTagEpcOver() {
            @Override
            public void log(String s, LogBaseEpcOver logBaseEpcOver) {
                System.out.println("通道门-搜索标签结束" + System.currentTimeMillis());
                log.info("搜索标签结束" + System.currentTimeMillis());
                // 上报
                if (isIn != null) {
                    onInout(isIn, new ArrayList<TagInfo>(tagSet));
                    isIn = null;
                }
            }
        };
        gClient.onGpiStart = new HandlerGpiStart() {
            @Override
            public void log(String s, LogAppGpiStart logAppGpiStart) {
                System.out.println("GPI:" + logAppGpiStart.getGpiPort() + "  " + System.currentTimeMillis());
                if (firstLogAppGpiStart != null && logAppGpiStart.getSystemTime().getTime() - firstLogAppGpiStart.getSystemTime().getTime() > 3000) {
                    firstLogAppGpiStart = null;
                    isIn = null;
                    tagSet.clear();
                }
                if (firstLogAppGpiStart == null) {
                    firstLogAppGpiStart = logAppGpiStart;
                    startRead();
                } else if (firstLogAppGpiStart.getGpiPort() != logAppGpiStart.getGpiPort()) {
                    if (isIn != null) {
                        return;
                    }
                    stopRead();
                    // false 主门在右侧 ，true 主门在左侧
                    boolean direction = mainConfig.getDoorDirection().equals("left");
                    isIn = firstLogAppGpiStart.getGpiPort() == (direction ? 1 : 0);
                } else {
                    firstLogAppGpiStart = logAppGpiStart;
                }
            }
        };


        searchCOM();
    }

    @Transactional(rollbackFor = Exception.class)
    public void onInout(boolean isIn, ArrayList<TagInfo> tagInfos) {
        if (tagInfos.isEmpty()) {
            return;
        }
        log.info(isIn ? "入" : "出" + "     " + tagInfos.size());

        // 查询档案盒 arc_box

        List<String> epcList = tagInfos.stream()
                .map(TagInfo::getEpc)
                .collect(Collectors.toList());

        if (epcList.size() > 0) {
            List<ArcBox> arcBoxes = arcBoxService.selectArcBoxListByRfid(epcList);
            log.info("查询档案盒数量：" + arcBoxes.size());
            for (ArcBox arcBox : arcBoxes) {
                System.out.println(arcBox.getBoxCode());
                log.info("查询档案盒：" + arcBox.getBoxCode());
            }

            List<ArchiveBoxInoutdetail> boxList = new ArrayList<>();

            if (arcBoxes != null && arcBoxes.size() > 0) {
                // 添加出入库记录
                ArchiveBoxInoutRecords archiveBoxInoutRecords = new ArchiveBoxInoutRecords();
                archiveBoxInoutRecords.setOrgNo(mainConfig.getOrgNo());
                archiveBoxInoutRecords.setRoomNo(mainConfig.getRoomNo());
                archiveBoxInoutRecords.setRecTime(DateUtils.getNowDate());
                archiveBoxInoutRecords.setType(isIn ? ArchiveBoxInoutRecords.BOX_IN : ArchiveBoxInoutRecords.BOX_OUT);
                archiveBoxInoutRecords.setPushStatus(MainConfig.PUSH_WAIT);

                int result = archiveBoxInoutRecordsService.insertArchiveBoxInoutRecords(archiveBoxInoutRecords);
                log.info("插入出入库记录：" + result);
                if (result > 0) {
                    boolean isNeedAlarm = false;

                    List<ArchiveBoxInoutRecords> archiveBoxInoutRecordsList = new ArrayList<>();
                    for (ArcBox arcBox : arcBoxes) {
                        log.info("arcBox" + arcBox.getBoxCode());
                        log.info("档案盒状态" + arcBox.getGiveBackStatus());
                        log.info("ArcBox.GIVE_BACK_STATUS_GIVEN" + ArcBox.GIVE_BACK_STATUS_GIVEN);
                        // 已借阅状态允许带出
                        if (!arcBox.getGiveBackStatus().equals(ArcBox.GIVE_BACK_STATUS_GIVEN)) {
                            isNeedAlarm = true;
                        }
                        ArchiveBoxInoutdetail archiveBoxInoutdetail = new ArchiveBoxInoutdetail();
                        archiveBoxInoutdetail.setRecordId(archiveBoxInoutRecords.getId());
                        archiveBoxInoutdetail.setBoxNo(arcBox.getBoxCode());
                        // 添加详情
                        archiveBoxInoutDetailService.insertArchiveBoxInoutdetail(archiveBoxInoutdetail);
                        boxList.add(archiveBoxInoutdetail);
                    }
                    archiveBoxInoutRecords.setBoxList(boxList);
                    //todo 档案室档案盒进出记录上报接口--不用上报
                    // archiveBoxInoutRecordsService.reportArchiveBoxInoutRecords(archiveBoxInoutRecords);
                    log.info(" isNeedAlarm " + isNeedAlarm);
                    if (isNeedAlarm && !isIn) {

                        lightRed();
                        //添加非法携带记录
                        ArchiveBoxIllegalRecords archiveBoxIllegalRecords = new ArchiveBoxIllegalRecords();
                        archiveBoxIllegalRecords.setOrgNo(mainConfig.getOrgNo());
                        archiveBoxIllegalRecords.setRoomNo(mainConfig.getRoomNo());
                        archiveBoxIllegalRecords.setAlarmTime(DateUtils.getNowDate());
                        archiveBoxIllegalRecords.setPushStatus(BusinessConstants.PUSHSTATUS);
                        archiveBoxIllegalRecordsService.insertArchiveBoxIllegalRecords(archiveBoxIllegalRecords);
                        List<ArchiveBoxIllegalDetailRecords> boxListRecords = new ArrayList<>();
                        for (ArcBox arcBox : arcBoxes) {
                            ArchiveBoxIllegalDetailRecords archiveBoxIllegalDetailRecords = new ArchiveBoxIllegalDetailRecords();
                            archiveBoxIllegalDetailRecords.setRecordId(archiveBoxIllegalRecords.getId());
                            archiveBoxIllegalDetailRecords.setBoxNo(arcBox.getBoxCode());
                            boxListRecords.add(archiveBoxIllegalDetailRecords);
                            archiveBoxIllegalDetailRecordsService.insertArchiveBoxIllegalDetailRecords(archiveBoxIllegalDetailRecords);
                        }
                        archiveBoxIllegalRecords.setBoxList(boxListRecords);
                        //todo 非法携带档案记录上报接口
                        //archiveBoxIllegalRecordsService.reportArchiveBoxIllegalRecords(archiveBoxIllegalRecords);
                    }
                }
            }
        }

    }

    private void startRead() {
        executorService.submit(() -> {
            if(isReading){
                return;
            }
            MsgBaseInventoryEpc msgBaseInventoryEpc = new MsgBaseInventoryEpc();
            msgBaseInventoryEpc.setAntennaEnable(EnumG.AntennaNo_1 | EnumG.AntennaNo_2 | EnumG.AntennaNo_3 | EnumG.AntennaNo_4);
            msgBaseInventoryEpc.setInventoryMode(EnumG.InventoryMode_Inventory);

            gClient.sendSynMsg(msgBaseInventoryEpc);
            if (0x00 == msgBaseInventoryEpc.getRtCode()) {
                isReading= true;
                System.out.println("通道门-开始读卡成功");
            } else {
                System.out.println("通道门-开始读卡失败");
                //isConnect = false;
                //gClient.close();
                // 如果开始读卡失败，一直循环开始读卡指令，如果成功则跳出循环
                for (int i = 0; i < 10; i++) {
                    System.out.println("通道门-开始读卡失败，第" + i + "次重试");
                    if (0x00 == msgBaseInventoryEpc.getRtCode()) {
                        isReading= true;
                        break;
                    }
                    gClient.sendSynMsg(msgBaseInventoryEpc);
                }
            }
        });
    }

    private void stopRead() {
        executorService.submit(() -> {
            if (!isReading){
                return;
            }
            try {
                Thread.sleep(1200);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            MsgBaseStop stopMsg = new MsgBaseStop();
            gClient.sendSynMsg(stopMsg);
            if (0x00 == stopMsg.getRtCode()) {
                System.out.println("通道门-停止读卡成功");
                isReading= false;
            } else {
                System.out.println("通道门-停止读卡失败");
                for (int i = 0; i < 10; i++) {
                    System.out.println("通道门-停止读卡失败，第" + i + "次重试");
                    if (0x00 == stopMsg.getRtCode()) {
                        isReading= false;
                        break;
                    }
                    gClient.sendSynMsg(stopMsg);
                }
            }
        });
    }

    private void lightGreen() {
        tagLight(1);
    }

    private void lightRed() {
        tagLight(2);
    }

    private void tagLight(int gpo) {
        executorService.submit(() -> {
            if (gClient != null) {
                // 立式通道  gpo 1 绿灯 gpo 2 红灯
                MsgAppSetGpo msgAppSetGpo = new MsgAppSetGpo();
                if (gpo == 1) {
                    msgAppSetGpo.setGpo1(1);

                } else if (gpo == 2) {
                    msgAppSetGpo.setGpo2(1);
                }
                msgAppSetGpo.setKeepTime(1500);
                gClient.sendSynMsg(msgAppSetGpo);
                //查询gpo状态
                if (0x00 == msgAppSetGpo.getRtCode()) {
                    System.out.println("通道门-gpo" + gpo + "高设置成功");
                } else {
                    System.out.println("通道门-gpo" + gpo + "高设置失败");
                    for (int i = 0; i < 10; i++) {
                        System.out.println("通道门-gpo高设置，第" + i + "次重试");
                        if (0x00 == msgAppSetGpo.getRtCode()) {
                            break;
                        }
                        gClient.sendSynMsg(msgAppSetGpo);
                    }
                }

//                try {
//                    Thread.sleep(1000);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//
//                if (gpo == 1) {
//                    msgAppSetGpo.setGpo1(0);
//                } else if (gpo == 2) {
//                    msgAppSetGpo.setGpo2(0);
//                }
//                gClient.sendSynMsg(msgAppSetGpo);
//                //查询gpio状态
//                if (0x00 == msgAppSetGpo.getRtCode()) {
//                    System.out.println("通道门-gpo" + gpo + "低设置成功");
//                } else {
//                    System.out.println("通道门-gpo" + gpo + "低设置失败");
//                    for (int i = 0; i < 10; i++) {
//                        System.out.println("通道门-gpo低设置，第" + i + "次重试");
//                        if (0x00 == msgAppSetGpo.getRtCode()) {
//                            break;
//                        }
//                        gClient.sendSynMsg(msgAppSetGpo);
//                    }
//                }
            }
        });
    }

    /**
     * 搜索
     */
    public void searchCOM() {
        new Thread(new Runnable() {
            @Override
            public void run() {

                //SerialPort[] ports = SerialPort.getCommPorts();
                //
                //for (SerialPort port : ports) {
                //    try {
                //        log.info(port.getSystemPortName());
                //        if(!isConnect && port.getDescriptivePortName().contains("USB")) {

                if (gClient.openJSerial485(mainConfig.getDoorNum())) {

                    log.info(mainConfig.getDoorNum() + "通道门连接成功");
                    isConnect = true;
                    MsgBaseStop msgBaseStop = new MsgBaseStop();
                    gClient.sendSynMsg(msgBaseStop);
                    if (0 == msgBaseStop.getRtCode()) {
                        System.out.println("通道门-停止读卡成功");
                    } else {
                        System.out.println("通道门-停止读卡失败");
                        for (int i = 0; i < 10; i++) {
                            System.out.println("通道门-停止读卡失败，第" + i + "次重试");
                            if (0x00 == msgBaseStop.getRtCode()) {
                                break;
                            }
                            gClient.sendSynMsg(msgBaseStop);
                        }
                    }
//                            MsgBaseInventoryEpc msgBaseInventoryEpc = new MsgBaseInventoryEpc();
//                            msgBaseInventoryEpc.setAntennaEnable(EnumG.AntennaNo_1 | EnumG.AntennaNo_2 | EnumG.AntennaNo_3 | EnumG.AntennaNo_4);
//                            msgBaseInventoryEpc.setInventoryMode(EnumG.InventoryMode_Inventory);
//
//                            gClient.sendSynMsg(msgBaseInventoryEpc);
//                                break;
                }
                //        }
                //    } catch (Exception exception) {
                //    }
                //}
            }
        }).start();
    }


    public static void main(String[] args) {
        GClient gClient = new GClient();
        if (gClient.openJSerial485("COM6:9600:1")) {
            //获取设备ip和端口号
            System.out.println("启动成功！");
        } else {
            System.out.println("启动失败！");
        }
        gClient.setSendHeartBeat(true);
        gClient.onDisconnected = new HandlerTcpDisconnected() {
            @Override
            public void log(String s) {
                System.out.println("通道门断开连接");
            }
        };
        gClient.onTagEpcLog = new HandlerTagEpcLog() {
            @Override
            public void log(String s, LogBaseEpcInfo logBaseEpcInfo) {
                System.out.println("收到标签");
            }
        };
        gClient.onTagEpcOver = new HandlerTagEpcOver() {
            @Override
            public void log(String s, LogBaseEpcOver logBaseEpcOver) {
                System.out.println("搜索标签结束" + System.currentTimeMillis());

            }
        };
        gClient.onGpiStart = new HandlerGpiStart() {
            @Override
            public void log(String s, LogAppGpiStart logAppGpiStart) {
                System.out.println("GPI:" + logAppGpiStart.getGpiPort() + "  " + System.currentTimeMillis());
                if (firstLogAppGpiStart != null && logAppGpiStart.getSystemTime().getTime() - firstLogAppGpiStart.getSystemTime().getTime() > 3000) {
                    firstLogAppGpiStart = null;
                    isIn = null;
                    tagSet.clear();
                }
                if (firstLogAppGpiStart == null) {
                    firstLogAppGpiStart = logAppGpiStart;
                    System.out.println("开始读卡");
                } else if (firstLogAppGpiStart.getGpiPort() != logAppGpiStart.getGpiPort()) {
                    if (isIn != null) {
                        return;
                    }
                    System.out.println("停止读卡");
                    // false 主门在右侧 ，true 主门在左侧
                    boolean direction = true;
                    isIn = firstLogAppGpiStart.getGpiPort() == (direction ? 0 : 1);
                } else {
                    firstLogAppGpiStart = logAppGpiStart;
                }
                System.out.println(isIn ? "进" : "出");
            }
        };
        // 最后一个
//        SerialPort[] ports = SerialPort.getCommPorts();

        Scanner scanner = new Scanner(System.in);
        scanner.hasNext();
    }

    /**
     * 定时任务
     */
    public void execute() {
        if (!isConnect) {
            searchCOM();
        }
    }
}
